package com.piece.module.generator.support;

import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.piece.core.framework.util.string.LambdaUtil;
import com.piece.core.framework.util.string.StringUtil;
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JFieldVar;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import org.jsonschema2pojo.AbstractTypeInfoAwareAnnotator;
import org.jsonschema2pojo.GenerationConfig;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.Set;

@Setter
public class DefaultTypeInfoAnnotator extends AbstractTypeInfoAwareAnnotator {

    /**
     * 是否开启使用lombok注解
     */
    boolean lombokAnnotationFlag = true;

    /**
     * 是否开启使用swagger注解
     */
    boolean swaggerAnnotationFlag = true;

    /**
     * 是否开启使用JPA注解
     */
    boolean jpaAnnotationFlag = true;

    /**
     * 是否开启使用mybatisplus注解
     */
    boolean mybatisPlusAnnotationFlag = false;

    /**
     * 是否开启使用jackson注解
     */
    boolean jacksonAnnotationFlag = true;

    public DefaultTypeInfoAnnotator(GenerationConfig generationConfig) {
        super(generationConfig);
    }

    @Override
    protected void addJsonTypeInfoAnnotation(JDefinedClass definedClass, String propertyName) {
    }

    public void propertyInclusion(JDefinedClass clazz, JsonNode schema) {
        if (lombokAnnotationFlag) {
            clazz.annotate(Data.class);
            clazz.annotate(Builder.class);
            clazz.annotate(NoArgsConstructor.class);
            clazz.annotate(AllArgsConstructor.class);
            //clazz.annotate(ToString.class).param(LambdaUtil.getMethodName(ToString::callSuper), true);
        }
        if (jpaAnnotationFlag) {
            clazz.annotate(Entity.class).param(LambdaUtil.getMethodName(Entity::name), StringUtil.toUnderScoreCase(clazz.name()));
            clazz.annotate(Table.class).param(LambdaUtil.getMethodName(Table::name), StringUtil.toUnderScoreCase(clazz.name()));
        }
//        if (mybatisPlusAnnotationFlag) {
//            clazz.annotate(TableName.class).param(LambdaUtil.getMethodName(TableName::value), StringUtil.toUnderScoreCase(clazz.name()));
//        }
        if (swaggerAnnotationFlag) {
            clazz.annotate(ApiModel.class).param(LambdaUtil.getMethodName(ApiModel::value), StringUtil.string(schema.get("description").asText("").getBytes()));
        }
    }

    public void propertyField(JFieldVar field, JDefinedClass clazz, String propertyName, JsonNode propertyNode) {
        if (jacksonAnnotationFlag) {
            if (field.type().erasure().equals(field.type().owner().ref(Date.class)) ||
                    field.type().erasure().equals(field.type().owner().ref(java.sql.Date.class))) {
                field.annotate(JSONField.class).param("format", "yyyy-MM-dd HH:mm:ss");
                field.annotate(JsonFormat.class).param("pattern", "yyyy-MM-dd HH:mm:ss").param("timezone", "GMT+8");
            }

            if (field.type().erasure().equals(field.type().owner().ref(Set.class))) {
                field.annotate(JsonDeserialize.class).param("as", LinkedHashSet.class);
            }

            if (propertyNode.has("javaJsonView")) {
                field.annotate(JsonView.class).param("value", field.type().owner().ref(propertyNode.get("javaJsonView").asText("")));
            }
        }
        if (jpaAnnotationFlag) {
            field.annotate(Column.class).param("value", StringUtil.toUnderScoreCase(clazz.name()));
        }
//        if (mybatisPlusAnnotationFlag) {
//            field.annotate(TableField.class).param("value", StringUtil.toUnderScoreCase(propertyName));
//        }
        if (swaggerAnnotationFlag) {
            field.annotate(ApiModelProperty.class).param(LambdaUtil.getMethodName(ApiModel::value), propertyNode.get("description").asText());
        }
    }
}
